﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;

namespace SteveDower.SimpleBacklog
{
    /// <summary>
    /// Interaction logic for BacklogView.xaml
    /// </summary>
    public partial class BacklogView : UserControl
    {
        #region Commands

        public static RoutedCommand SetStatusTesting = new RoutedCommand();
        public static RoutedCommand SetStatusWorking = new RoutedCommand();
        public static RoutedCommand SetStatusDeferred = new RoutedCommand();
        public static RoutedCommand SetStatusUnstarted = new RoutedCommand();
        public static RoutedCommand SetStatusCompleted = new RoutedCommand();
        public static RoutedCommand SetPriorityCritical = new RoutedCommand();
        public static RoutedCommand SetPriorityImportant = new RoutedCommand();
        public static RoutedCommand SetPriorityWishlist = new RoutedCommand();

        public static RoutedCommand DeleteItem = new RoutedCommand();

        private CommandBinding CreateSetStatusBinding(Status status)
        {
            return new CommandBinding(
                status == Status.Testing ? SetStatusTesting :
                status == Status.Working ? SetStatusWorking :
                status == Status.Deferred ? SetStatusDeferred :
                status == Status.Unstarted ? SetStatusUnstarted :
                status == Status.Completed ? SetStatusCompleted :
                null,
                new ExecutedRoutedEventHandler((s, e) => 
                {
                    ((BacklogItem)e.Parameter).Status = status;
                    FilteredItems_Invalidate(null, null);
                }),
                new CanExecuteRoutedEventHandler((s, e) =>
                {
                    var bi = e.Parameter as BacklogItem;
                    e.CanExecute = (bi != null && bi.Status != status);
                }));
        }

        private CommandBinding CreateSetPriorityBinding(Priority priority)
        {
            return new CommandBinding(
                priority == Priority.Critical ? SetPriorityCritical :
                priority == Priority.Important ? SetPriorityImportant :
                priority == Priority.Wishlist ? SetPriorityWishlist :
                null,
                new ExecutedRoutedEventHandler((s, e) =>
                {
                    ((BacklogItem)e.Parameter).Priority = priority;
                    FilteredItems_Invalidate(null, null);
                }),
                new CanExecuteRoutedEventHandler((s, e) =>
                {
                    var bi = e.Parameter as BacklogItem;
                    e.CanExecute = (bi != null && bi.Priority != priority);
                }));
        }

        private void InitCommandBindings()
        {
            foreach(var cb in Enum.GetValues(typeof(Priority)).Cast<Priority>().Select(CreateSetPriorityBinding))
            {
                CommandBindings.Add(cb);
            }
            foreach (var cb in Enum.GetValues(typeof(Status)).Cast<Status>().Select(CreateSetStatusBinding))
            {
                CommandBindings.Add(cb);
            }

            CommandBindings.Add(new CommandBinding(DeleteItem, new ExecutedRoutedEventHandler(DeleteItem_Executed),
                new CanExecuteRoutedEventHandler((o, e) => { e.CanExecute = e.Parameter is BacklogItem; })));
        }

        private void DeleteItem_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            var bi = (BacklogItem)e.Parameter;
            Items.Remove(bi);
        }

        #endregion

        public BacklogView()
        {
            Items = new ObservableCollection<BacklogItem>();
            DataContext = Items;
            
            InitializeComponent();

            InitCommandBindings();
            Focus();

            PriorityMap = new Dictionary<Priority, CheckBox>
            {
                { Priority.Critical, chkShowCritical },
                { Priority.Important, chkShowImportant },
                { Priority.Wishlist, chkShowWishlist }
            };
        }

        public void SetItems(IEnumerable<BacklogItem> items)
        {
            Items.Clear();
            if (items != null)
            {
                foreach (var item in items) Items.Add(item);
            }
        }

        public ObservableCollection<BacklogItem> Items
        {
            get { return (ObservableCollection<BacklogItem>)GetValue(ItemsProperty); }
            set { SetValue(ItemsProperty, value); }
        }

        public static readonly DependencyProperty ItemsProperty =
            DependencyProperty.Register("Items", typeof(ObservableCollection<BacklogItem>), typeof(BacklogView), new UIPropertyMetadata(null));



        private void NewCriticalItem(object sender, RoutedEventArgs e)
        {
            Items.Add(new BacklogItem(Priority.Critical));
        }

        private void NewImportantItem(object sender, RoutedEventArgs e)
        {
            Items.Add(new BacklogItem(Priority.Important));
        }

        private void NewWishlistItem(object sender, RoutedEventArgs e)
        {
            Items.Add(new BacklogItem(Priority.Wishlist));
        }

        private readonly IDictionary<Priority, CheckBox> PriorityMap;

        private void FilteredItems_Filter(object sender, FilterEventArgs e)
        {
            var bi = e.Item as BacklogItem;
            if (bi == null) e.Accepted = false;
            else e.Accepted = PriorityMap[bi.Priority].IsChecked ?? false;

            if (e.Accepted == false) return;

            switch (lstStatusFilter.SelectedIndex)
            {
            case 0:     // All items
                e.Accepted = true;
                break;
            case 1:     // Active items
                e.Accepted = bi.Status == Status.Working || bi.Status == Status.Testing;
                break;
            case 2:     // Unstarted items
                e.Accepted = bi.Status == Status.Unstarted;
                break;
            case 3:     // Completed items
                e.Accepted = bi.Status == Status.Completed;
                break;
            default:
                break;
            }
        }

        private void FilteredItems_Invalidate(object sender, RoutedEventArgs e)
        {
            CollectionViewSource v = (CollectionViewSource)FindResource("FilteredItems");
            v.View.Refresh();
        }

        private void txt_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
        {
            var tb = sender as TextBox;
            if (tb != null) tb.SelectAll();
        }

        private int LastMouseDown = 0;
        private void Item_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (e.Timestamp - LastMouseDown <= System.Windows.Forms.SystemInformation.DoubleClickTime)
            {
                var bi = ((FrameworkElement)sender).Tag as BacklogItem;
                if (bi != null)
                {
                    if (bi.Status == Status.Unstarted) bi.Status = Status.Working;
                    else if (bi.Status == Status.Working) bi.Status = Status.Testing;
                    else if (bi.Status == Status.Deferred) bi.Status = Status.Working;
                    else if (bi.Status == Status.Testing) bi.Status = Status.Completed;
                }
            }
            LastMouseDown = e.Timestamp;
        }

    }

    public class EnumToResourceConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            var element = (FrameworkElement)parameter;
            return element.FindResource(value.ToString());
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    public class StringToVisibilityConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            var vis = (Visibility)parameter;
            if (string.IsNullOrEmpty(value as string) && vis == Visibility.Visible)
            {
                return Visibility.Hidden;
            }
            else
            {
                return Visibility.Visible;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

}